<template>
  <div
    ref="container"
    :class="['progressive-bg', { loaded }]"
    :style="containerStyle"
  >
    <slot />
  </div>
</template>

<script lang="ts" setup>
import { ref, computed, onMounted, defineProps } from "vue";

interface Props {
  src: string;
  width?: string | number;
  height?: string | number;
  fit?: "cover" | "contain" | "fill" | "none" | "scale-down";
  position?: string;
  lazy?: boolean;
  fallback?: string;
  compress?: boolean;
  quality?: number;
}

const props = withDefaults(defineProps<Props>(), {
  fit: "cover",
  position: "center",
  lazy: true,
  width: "100%",
  height: "300px",
  fallback: "",
  compress: true,
  quality: 0.7
});

const container = ref<HTMLElement | null>(null);
const loaded = ref(false);
const containerStyle = ref<Record<string, string>>({});

function resolveSrc(src: string) {
  if (!src) return "";
  if (/^https?:\/\//.test(src)) return src;
  if (src.startsWith("@/")) {
    try {
      return new URL(src.replace(/^@/, "/src"), import.meta.url).href;
    } catch {
      console.warn("[ProgressiveBackground] 无法解析 @ 路径:", src);
    }
  }
  if (src.startsWith("./") || src.startsWith("../")) {
    try {
      return new URL(src, import.meta.url).href;
    } catch {
      console.warn("[ProgressiveBackground] 无法解析相对路径:", src);
    }
  }
  if (src.startsWith("/")) return src;
  return src;
}

/**
 * 自动生成低清模糊图
 */
async function generateLowRes(
  src: string,
  scale = 0.1,
  quality = 0.4
): Promise<string> {
  try {
    const path = resolveSrc(src);
    const blob = await fetch(path).then(r => {
      if (!r.ok) throw new Error("无法加载图片");
      return r.blob();
    });
    const bitmap = await createImageBitmap(blob);
    const canvas = document.createElement("canvas");
    canvas.width = Math.max(1, bitmap.width * scale);
    canvas.height = Math.max(1, bitmap.height * scale);
    const ctx = canvas.getContext("2d")!;
    ctx.drawImage(bitmap, 0, 0, canvas.width, canvas.height);
    return canvas.toDataURL("image/jpeg", quality);
  } catch (err) {
    console.warn("[ProgressiveBackground] 低清图生成失败:", err);
    return "";
  }
}

/**
 * 加载高清图并替换背景
 */
async function loadHighRes() {
  if (!container.value) return;
  const el = container.value;

  // 设置低清图
  let lowRes = "";
  if (props.compress) {
    lowRes = await generateLowRes(props.src);
    if (lowRes) el.style.backgroundImage = `url(${lowRes})`;
  }

  // 设置基础样式
  containerStyle.value = {
    width: typeof props.width === "number" ? `${props.width}px` : props.width!,
    height:
      typeof props.height === "number" ? `${props.height}px` : props.height!,
    backgroundSize: props.fit,
    backgroundPosition: props.position!,
    backgroundRepeat: "no-repeat",
    transition: "opacity 0.6s ease",
    backgroundImage: lowRes ? `url(${lowRes})` : ""
  };

  // 加载高清图
  const img = new Image();
  img.src = resolveSrc(props.src);
  img.onload = () => {
    el.style.opacity = "0";
    setTimeout(() => {
      el.style.backgroundImage = `url(${img.src})`;
      el.style.opacity = "1";
      loaded.value = true;
    }, 50);
  };
  img.onerror = () => {
    if (props.fallback)
      el.style.backgroundImage = `url(${resolveSrc(props.fallback)})`;
    loaded.value = true;
  };
}

onMounted(() => {
  if (props.lazy && container.value) {
    const observer = new IntersectionObserver(
      entries => {
        entries.forEach(entry => {
          if (entry.isIntersecting) {
            loadHighRes();
            observer.disconnect();
          }
        });
      },
      { threshold: 0.1 }
    );
    observer.observe(container.value);
  } else {
    loadHighRes();
  }
});
</script>

<style scoped>
.progressive-bg {
  position: relative;
  overflow: hidden;
  opacity: 1;
  transition: opacity 0.6s ease;
}

.progressive-bg.loaded {
  opacity: 1;
}
</style>
